﻿using UnityEngine;
using static CGF.ScrollView;

namespace CGF
{
    public class ScrollViewDirVertical : ScrollViewDirBase
    {
        public ScrollViewDirVertical(ScrollView main) : base(main)
        {
        }

        public override void UpdateCellsPos(float x, float y, Cell[] cells)
        {
            if (cells.Length > 0)
            {
                for (int i = 0; i < cells.Length; i++)
                {
                    Cell cell = cells[i];
                    if (cell != null && cell.trans)
                    {
                        Vector2 pos;
                        if (i == 0)
                        {
                            pos.x = x + cell.Width * 0.5f;
                            pos.y = y - cell.Height * 0.5f;
                        }
                        else
                        {
                            Cell preCell = cells[i - 1];
                            pos.x = preCell.trans.anchoredPosition.x + preCell.Width * 0.5f + main.space.x + cell.Width * 0.5f;
                            pos.y = y - cell.Height * 0.5f;
                        }
                        cell.trans.anchoredPosition = pos;
                    }
                }
            }
        }

        public override void RefreshSize(Cell[] cells, ref float w, ref float h)
        {
            h = 0;
            for (int i = 0; i < cells.Length; i++)
            {
                Cell cell = cells[i];
                if (cell.trans)
                {
                    if (cell != null && cell.trans.gameObject.activeSelf && cell.Height > h)
                    {
                        h = cell.Height;
                    }
                }
            }
        }

        public override (float x, float y) GetInitPos()
        {
            float x, y;
            if (main.endRow == null)
            {
                x = main.space.x;
                y = -main.space.y;
            }
            else
            {
                x = main.endRow.x;
                y = main.endRow.y - main.endRow.height - main.space.y;
            }

            return (x, y);
        }

        public override bool HasFull()
        {
            return main.endRow.y - main.endRow.height < -main.viewportSize.y;
        }

        public override void SetRowPos(Row row)
        {
            if (main.headRow == null)
            {
                row.y = -main.viewportSize.y + main.space.y + row.height;
            }
            else
            {
                row.y = main.headRow.y + main.space.y + row.height;
            }
        }

        public override bool CanBreak()
        {
            return main.headRow.y > -main.space.y;
        }

        public override bool SetXY(Row row, ref float x, ref float y)
        {
            y -= (row.height + main.space.y);
            if (main.endRow.y - main.endRow.height < -main.viewportSize.y)
            {
                return true;
            }

            return false;
        }

        public override bool IsCellsExceedsView()
        {
            float contentHeight = 0;
            for (int i = 0; i < main.rows.Count; i++)
            {
                if (i > 0)
                {
                    contentHeight += main.space.y;
                }

                contentHeight += main.rows[i].height;
            }

            float containerHeight = main.viewportSize.y - main.space.y;
            return contentHeight > containerHeight;
        }

        public override void ReduceSpeed()
        {
            if (main.velocity < 0)
            {
                //下移
                if (main.headRow.y < -main.space.y)
                {
                    main.velocityScale = (endActiveDis.y + main.headRow.y + main.space.y) / endActiveDis.y;
                    if (!main.hasTriggerHeadAction)
                    {
                        main._onScrollToHead?.Invoke();
                        main.hasTriggerHeadAction = true;
                    }
                }
                else
                {
                    main.velocityScale = 1;
                }
            }
            else if (main.velocity > 0)
            {
                //上移
                if (main.cellsExceedsView)
                {
                    //内容铺满超过视窗的情况，监听下端减速
                    if (main.endRow.y - main.endRow.height > -main.viewportSize.y + main.space.y)
                    {
                        main.velocityScale = (endActiveDis.y - (main.endRow.y - main.endRow.height + main.viewportSize.y - main.space.y)) / endActiveDis.y;
                        if (!main.hasTriggerEndAction)
                        {
                            main._onScrollToEnd?.Invoke();
                            main.hasTriggerEndAction = true;
                        }
                    }
                    else
                    {
                        main.velocityScale = 1;
                    }
                }
                else
                {
                    //全内容不能铺满视窗的情况，监听上段减速
                    if (main.headRow.y > -main.space.y)
                    {
                        main.velocityScale = (-main.space.y + endActiveDis.y - main.headRow.y) / endActiveDis.y;
                        if (!main.hasTriggerEndAction)
                        {
                            main._onScrollToEnd?.Invoke();
                            main.hasTriggerEndAction = true;
                        }
                    }
                    else
                    {
                        main.velocityScale = 1;
                    }
                }
            }
        }

        public override bool ElasticBack(float elastic)
        {
            if (main.headRow.y + main.space.y < -1)
            {
                //上端从内部回弹
                main.velocity = (0 - (main.headRow.y + main.space.y)) * elastic;
                return true;
            }

            if (main.cellsExceedsView)
            {
                //内容铺满超过视窗的情况，下端从内部回弹
                if (main.endRow.y - main.endRow.height - main.space.y > -main.viewportSize.y + 1)
                {
                    main.velocity = -(main.endRow.y - main.endRow.height - main.space.y + main.viewportSize.y) * elastic;
                    return true;
                }
            }
            else
            {
                //内容不能铺满视窗的情况，上端从外部回弹
                if (main.headRow.y + main.space.y > 1)
                {
                    main.velocity = -(main.headRow.y + main.space.y) * elastic;
                    return true;
                }
            }

            return false;
        }

        public override void MoveHeadRow()
        {
            main.headRow.y += main.velocity * main.velocityScale;
        }

        public override void MoveFollowHeadRow(Row row, Row preRow)
        {
            row.y = preRow.y - preRow.height - main.space.y;
        }

        public override void Reuse()
        {
            if (main.velocity > 0)
            {
                //上移
                if (main.headRow.y - main.headRow.height > 0)
                {
                    //上端
                    main.rows.RemoveAt(0);
                    main.headRow.OnRecycle();
                    main.pool.Enqueue(main.headRow);
                    main.headRow = main.rows[0];
                }

                if (main.endRow.y - main.endRow.height > -main.viewportSize.y)
                {
                    //下端
                    int nextIndex = main.endRow.GetEndCellIndex() + 1;
                    if (nextIndex > 1 && nextIndex < main.totalDataCount)
                    {
                        float x = main.endRow.x;
                        float y = main.endRow.y - main.endRow.height - main.space.y;
                        Row newEndRow = null;
                        if (main.pool.Count > 0)
                        {
                            newEndRow = main.pool.Dequeue();
                            newEndRow.OnReuse(x, y, ref nextIndex);
                        }
                        else
                        {
                            newEndRow = main._CreateNewRow(x, y, ref nextIndex);
                        }

                        main.rows.Add(newEndRow);
                        main.endRow = newEndRow;
                    }
                }
            }
            else if (main.velocity < 0)
            {
                //下移
                if (main.endRow.y < -main.viewportSize.y)
                {
                    //下端
                    main.rows.RemoveAt(main.rows.Count - 1);
                    main.endRow.OnRecycle();
                    main.pool.Enqueue(main.endRow);
                    main.endRow = main.rows[main.rows.Count - 1];
                }

                if (main.headRow.y < 0)
                {
                    //上端
                    int nextIndex = main.headRow.GetHeadCellIndex() - main.gridNum;
                    if (nextIndex >= 0)
                    {
                        float x = main.headRow.x;
                        float y = -99999;
                        Row newHeadRow = null;
                        if (main.pool.Count > 0)
                        {
                            newHeadRow = main.pool.Dequeue();
                            newHeadRow.OnReuse(x, y, ref nextIndex);
                        }
                        else
                        {
                            newHeadRow = main._CreateNewRow(x, y, ref nextIndex);
                        }

                        newHeadRow.y = main.headRow.y + main.space.y + newHeadRow.height;
                        main.rows.Insert(0, newHeadRow);
                        main.headRow = newHeadRow;
                    }
                }
            }
        }

        public override float GetTouchPos(Vector2 uiPos)
        {
            return uiPos.y;
        }

        public override Vector2 EditModeUpdatePos(RectTransform child, int rowIndex, int gridIndex)
        {
            Vector2 pos;
            pos.x = main.space.x + child.sizeDelta.x * 0.5f + (child.sizeDelta.x + main.space.x) * gridIndex;
            pos.y = -main.space.y - child.sizeDelta.y * 0.5f - (child.sizeDelta.y + main.space.y) * rowIndex;
            return pos;
        }
    }
}